package com.itstyle.quartz.web;

import com.itstyle.quartz.entity.JobLog;
import com.itstyle.quartz.entity.JobLogResp;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletResponse;

import org.apache.http.ParseException;
import org.apache.http.client.utils.DateUtils;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.itstyle.quartz.entity.QuartzEntity;
import com.itstyle.quartz.entity.Result;
import com.itstyle.quartz.service.IJobService;

@Api(tags = "Quartz任务")
@RestController
@RequestMapping("/job")
public class JobController {
    private final static Logger LOGGER = LoggerFactory.getLogger(JobController.class);


    @Autowired
    @Qualifier("Scheduler")
    private Scheduler scheduler;
    @Autowired
    private IJobService jobService;

    @SuppressWarnings({"unchecked", "rawtypes"})
    @ApiOperation(value = "新建任务")
    @PostMapping("/add")
    public Result save(QuartzEntity quartz) {
        LOGGER.info("新增任务");
        try {
            //获取Scheduler实例、废弃、使用自动注入的scheduler、否则spring的service将无法注入
            //Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            //如果是修改  展示旧的 任务
            if (quartz.getOldJobGroup() != null) {
                JobKey key = new JobKey(quartz.getOldJobName(), quartz.getOldJobGroup());
                scheduler.deleteJob(key);
            }
            Class cls = Class.forName(quartz.getJobClassName());
            cls.newInstance();
            //构建job信息
            JobDetail job = JobBuilder.newJob(cls).withIdentity(quartz.getJobName(),
                    quartz.getJobGroup()).usingJobData("jobUrl", quartz.getJobUrl())
                    .withDescription(quartz.getDescription()).build();

            // 触发时间点
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(quartz.getCronExpression());
            Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger" + quartz.getJobName(), quartz.getJobGroup())
                    .startNow().withSchedule(cronScheduleBuilder).build();
            //交由Scheduler安排触发
            scheduler.scheduleJob(job, trigger);
        } catch (ObjectAlreadyExistsException e) {
            LOGGER.error("异常", e);
            return Result.error("任务名已存在");
        } catch (ParseException e) {
            LOGGER.error("异常", e);
            return Result.error("执行时间表达式错误");
        } catch (RuntimeException e) {
            LOGGER.error("异常", e);
            return Result.error("执行时间表达式错误");
        } catch (Exception e) {
            LOGGER.error("异常", e);
            return Result.error();
        }
        return Result.ok();
    }

    @ApiOperation(value = "任务列表")
    @PostMapping("/list")
    public Result list(QuartzEntity quartz, Integer pageNo, Integer pageSize) {
        LOGGER.info("任务列表");
        List<QuartzEntity> list = jobService.listQuartzEntity(quartz, pageNo, pageSize);
        for (QuartzEntity entity : list) {
            try {
                entity.setJobDataMap((JobDataMap) byteToObject((byte[]) entity.getJobData()));
                entity.setJobUrl(entity.getJobDataMap().getString("jobUrl"));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return Result.ok(list);
    }

    @ApiOperation(value = "日志列表")
    @PostMapping("/listLog")
    public Result list(JobLog jobLog, Integer pageNo, Integer pageSize) {
        LOGGER.info("日志列表");
        List<JobLog> list = jobService.listJobLog(jobLog, pageNo, pageSize);
        List<JobLogResp> resps = new ArrayList<>(list.size());
        list.stream().forEach(log -> {
            JobLogResp resp = new JobLogResp();
            resp.setId(log.getId());
            resp.setJobName(log.getJobName());
            resp.setJobResult(log.getJobResult());
            resp.setJobUrl(log.getJobUrl());
            resp.setJobStatus(1 == log.getJobStatus() ? "成功" : "失败");
            resp.setCreateTime(DateUtils.formatDate(log.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
            resps.add(resp);
        });
        return Result.ok(resps);
    }

    /**
     * 对象转byte
     *
     * @param obj
     * @return
     */
    private byte[] objectToByte(Object obj) {
        byte[] bytes = null;
        try {
            // object to bytearray
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            ObjectOutputStream oo = new ObjectOutputStream(bo);
            oo.writeObject(obj);

            bytes = bo.toByteArray();

            bo.close();
            oo.close();
        } catch (Exception e) {
            System.out.println("translation" + e.getMessage());
            e.printStackTrace();
        }
        return bytes;
    }

    /**
     * byte转对象
     *
     * @param bytes
     * @return
     */
    private Object byteToObject(byte[] bytes) {
        Object obj = null;
        try {
            // bytearray to object
            ByteArrayInputStream bi = new ByteArrayInputStream(bytes);
            ObjectInputStream oi = new ObjectInputStream(bi);

            obj = oi.readObject();
            bi.close();
            oi.close();
        } catch (Exception e) {
            System.out.println("translation" + e.getMessage());
            e.printStackTrace();
        }
        return obj;
    }

    @ApiOperation(value = "触发任务")
    @PostMapping("/trigger")
    public Result trigger(QuartzEntity quartz, HttpServletResponse response) {
        try {
            JobKey key = new JobKey(quartz.getJobName(), quartz.getJobGroup());
            scheduler.triggerJob(key);
        } catch (SchedulerException e) {
            e.printStackTrace();
            return Result.error();
        }
        return Result.ok();
    }

    @PostMapping("/pause")
    public Result pause(QuartzEntity quartz, HttpServletResponse response) {
        LOGGER.info("停止任务");
        try {
            JobKey key = new JobKey(quartz.getJobName(), quartz.getJobGroup());
            scheduler.pauseJob(key);
        } catch (SchedulerException e) {
            e.printStackTrace();
            return Result.error();
        }
        return Result.ok();
    }

    @PostMapping("/resume")
    public Result resume(QuartzEntity quartz, HttpServletResponse response) {
        LOGGER.info("恢复任务");
        try {
            JobKey key = new JobKey(quartz.getJobName(), quartz.getJobGroup());
            scheduler.resumeJob(key);
        } catch (SchedulerException e) {
            e.printStackTrace();
            return Result.error();
        }
        return Result.ok();
    }

    @ApiOperation(value = "移除任务")
    @PostMapping("/remove")
    public Result remove(QuartzEntity quartz, HttpServletResponse response) {
        try {

            TriggerKey triggerKey = TriggerKey.triggerKey(quartz.getJobName(), quartz.getJobGroup());
            // 停止触发器  
            scheduler.pauseTrigger(triggerKey);
            // 移除触发器  
            scheduler.unscheduleJob(triggerKey);
            // 删除任务  
            scheduler.deleteJob(JobKey.jobKey(quartz.getJobName(), quartz.getJobGroup()));
            System.out.println("removeJob:" + JobKey.jobKey(quartz.getJobName()));
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error();
        }
        return Result.ok();
    }
}
